﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Sample.Novel.Application;
using Sample.Novel.Application.Contracts;
using Sample.Novel.Domain;
using Sample.Novel.Domain.Shared;
using Sample.Novel.EntityFrameworkCore;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using Volo.Abp;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Autofac;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.VirtualFileSystem;

namespace Sample.Novel.Web
{
    [DependsOn(
        typeof(AbpAutofacModule),
        typeof(AbpAspNetCoreMvcModule),
        typeof(NovelApplicationModule),
        typeof(NovelEntityFrameworkModule),
        typeof(AbpSwashbuckleModule),
        typeof(AbpAspNetCoreMvcUiBundlingModule)
        )]
    public class NovelWebMoudle
        :AbpModule
    {
        //程序已启动就配置管道
        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {
           var env = context.GetEnvironment();
            var app = context.GetApplicationBuilder();

            if (env.IsDevelopment()) { 
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseUnitOfWork();

            // Enable middleware to serve generated Swagger as a JSON endpoint
            app.UseSwagger(c => { c.RouteTemplate = "swagger/{documentName}/swagger.json"; });

            // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
            app.UseSwaggerUI(options =>
            {
                // specifying the Swagger JSON endpoint.
                options.SwaggerEndpoint($"/swagger/v1/swagger.json", $"Sample.Novel API V1");
                //options.IndexStream = () => Assembly.GetExecutingAssembly().GetManifestResourceStream("ABB.CustomerCareSystem.Web.Host.wwwroot.swagger.ui.index.html");
                options.DisplayOperationId();
                options.DisplayRequestDuration(); //显示请求持续时间
            });

            app.UseConfiguredEndpoints();
        }

        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var env = context.Services.GetHostingEnvironment();
            var configuration = context.Services.GetConfiguration();

            context.Services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "Sample.Novel API",
                    Description = "Sample.Novel",
                    // uncomment if needed TermsOfService = new Uri("https://example.com/terms"),
                });
                options.DocInclusionPredicate((docName, description) => true);

                options.CustomOperationIds(e =>
                    e.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null
                    );

                options.CustomOperationIds(e =>
                    e.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null
                    );
                // Define the BearerAuth scheme that's in use
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    Scheme = "bearer"
                });

                // 在header中添加token，传递到后台
                //options.OperationFilter<SecurityRequirementsOperationFilter>();


                // 使用反射获取xml文件。并构造出文件的路径;
                var baseDirectory = AppContext.BaseDirectory;
                var projectName = Assembly.GetExecutingAssembly().GetName().Name.RemovePostFix(".Web");
                var xmlPaths = new string[] {
                   "Application"
                }
                .Select(layer => Path.Combine(baseDirectory, $"{projectName}.{layer}.xml"))
                .ToList();
                // 启用xml注释. 该方法第二个参数启用控制器的注释，默认为false.
                xmlPaths.ForEach(xmlPath => options.IncludeXmlComments(xmlPath, true));
            });

            //发送完整错误到前端
            context.Services.Configure<AbpExceptionHandlingOptions>(options =>
            {
                options.SendExceptionsDetailsToClients = true;
            });

            //配置虚拟文件系统
            ConfigureVirtualFileSystem(context.Services.GetHostingEnvironment());
            ConfigureLocalizationServices();

            //配置Api控制器
            Configure<AbpAspNetCoreMvcOptions>(options => {
                options.ConventionalControllers
                .Create(typeof(NovelApplicationModule).Assembly, options => {
                    options.RootPath = "novel";
                });
            });
        }


        private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
        {
            if (hostingEnvironment.IsDevelopment())
            {
                Configure<AbpVirtualFileSystemOptions>(options =>
                {
                    options.FileSets.ReplaceEmbeddedByPhysical<NovelDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Sample.Novel.Domain.Shared"));
                    options.FileSets.ReplaceEmbeddedByPhysical<NovelDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Sample.Novel.Domain"));
                    options.FileSets.ReplaceEmbeddedByPhysical<NovelApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Sample.Novel.Application.Contracts"));
                    options.FileSets.ReplaceEmbeddedByPhysical<NovelApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Sample.Novel.Application"));
                    options.FileSets.ReplaceEmbeddedByPhysical<NovelWebMoudle>(hostingEnvironment.ContentRootPath);
                });
            }
        }

        /// <summary>
        /// 配置本地化
        /// </summary>
        private void ConfigureLocalizationServices()
        {
            Configure<AbpLocalizationOptions>(options =>
            {
                options.Languages.Add(new LanguageInfo("ar", "ar", "العربية"));
                options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština"));
                options.Languages.Add(new LanguageInfo("en", "en", "English"));
                options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)"));
                options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar"));
                options.Languages.Add(new LanguageInfo("fi", "fi", "Finnish"));
                options.Languages.Add(new LanguageInfo("fr", "fr", "Français"));
                options.Languages.Add(new LanguageInfo("hi", "hi", "Hindi", "in"));
                options.Languages.Add(new LanguageInfo("is", "is", "Icelandic", "is"));
                options.Languages.Add(new LanguageInfo("it", "it", "Italiano", "it"));
                options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português"));
                options.Languages.Add(new LanguageInfo("ro-RO", "ro-RO", "Română"));
                options.Languages.Add(new LanguageInfo("ru", "ru", "Русский"));
                options.Languages.Add(new LanguageInfo("sk", "sk", "Slovak"));
                options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe"));
                options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
                options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文"));
                options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
                options.Languages.Add(new LanguageInfo("es", "es", "Español"));
            });
        }
    }
}
